package com.cskaoyan.javase.oop1._6constructor;

/**
 * 创建一个教师类，有课程和年龄两个属性，行为是可以上课。
 * 现在我们需要创建以下对象：
 * 18岁的Java老师对象
 * 28岁的C++老师对象
 * 30岁的Python老师对象
 * ...
 * 按照之前我们的做法，需要先创建出对象，再进行成员变量的赋值。
 * 这样做如果只有一个两个对象还好，如果需要创建很多对象，就有点过于麻烦了。
 * 对象的属性，能不能"出厂"的时候就设定好呢？
 * 有这种需求时，就需要，构造方法（constructor，也叫构造器）来完成了。
 *
 * 构造方法（构造器）是Java面向对象，最最基础的一个语法概念了。
 * 但它虽然叫方法，但明显和普通方法不同。
 *
 * 构造方法也是方法，但属于一种特殊的方法，具有以下特点：
 * 语法结构和一般方法不同，如下：
 * [访问权限修饰符] 类名(形参列表){
 *   // 构造方法体
 * }
 *
 * 解释：
 *      1.它既然是方法,也定义在类体中的成员位置.
 *      2.访问权限修饰符我们还没有学习，这里我们默认它是public修饰的。
 *      3.类名的位置必须和当前类的类名完全一致。（类名是大驼峰的，这里也要大驼峰）
 *          这里可以看成是构造器的名字,也就是说构造器的名字要和类名保持一致
 *          构造方法没有返回值，也不需要写返回值类型。（你也写不了！当然它也不能用return结束方法/表示返回值）
 *       4.形参列表可以为空，称之为无参构造方法，简称无参构造。当然也可以有参数，是为有参构造。
 *       5.构造方法的方法体体，和成员方法类似，可以写语句,而且它同样隐含this传参
 *          指向当前对象
 *
 * 构造器的作用是什么呢?
 *      new对象过程中,是JVM在创建对象,我们把这个过程分成两大部分:
 *      a.创建对象结构本身,这个事情是JVM自己完成的,程序员几乎是不可控的
 *      b.创建对象完毕后成员变量的赋值,当然从语法上看,这个赋值是在创建对象过程中的赋值,程序员是可以控制的.
 *      构造器的作用:
 *      在Java中使用new关键字，创建对象，必然调用构造方法。
 *      构造器的作用是在创建对象过程中,用来给成员变量赋值的。
 *      切记,它的作用不是创建对象,它的作用是赋值.(给成员变量赋值)
 *
 * 既然new对象,就会调用构造器,那么诸如以下语法:
 *      Teacher t1 = new Teacher();
 * Teacher类中没有明确定义构造器,那么构造器哪里来的?
 * 这说明:
 * 一个类中，如果没有显式的给出一个构造方法（包括有参无参），那么就会默认提供一个无参构造方法,这是编译器编译代码自动加上去的。
 * 编译器自动添加的默认无参格式为:
 * public 类名(){
 * }
 *
 * 显然无参构造器,没有任何传参,它是无法完成赋值的
 * 要想完成赋值,需要有参构造器来完成
 *
 * 在Java中,有参构造器的格式(构造器中于是有this传参的):
 * [访问权限修饰符] 类名(数据类型 成员变量名1,数据类型 成员变量名2....){
 *     this.成员变量名1 = 成员变量名1;
 *     this.成员变量名2 = 成员变量名2;
 *     ...
 * }
 * 强调: 构造器的作用是赋值,在构造器调用时,给成员变量赋值时,对象的结构已经创建完毕了,构造器不是在创建对象
 *
 * 以上就是构造器的基本使用,接下来讲几个注意事项:
 * 1.构造器也是方法,一个类中可以定义多个构造器,这些构造器之间是方法的重载关系,要符合方法的重载语法.
 *
 * 2.(重点)当类中提供任何一个构造器,那么该类的默认无参就不会提供了.
 * 小建议: 如果一个类需要创建对象,那么建议在定义类时,顺手给类加上无参构造器,这会是一个好习惯.
 *
 * 3.(最重要的一点)
 * 使用(标准格式的有参)构造器在new对象过程中给成员变量赋值
 * 填入的实参数据是什么
 * 那么最终得到的成员变量取值就是什么
 * 这就是说,构造器的赋值是一定的,是肯定正确的
 * "你可以永远相信构造器"
 * 标准格式有参构造器:
 * [访问权限修饰符] 类名(数据类型 成员变量名1,数据类型 成员变量名2....){
 *     this.成员变量名1 = 成员变量名1;
 *     this.成员变量名2 = 成员变量名2;
 *     ...
 * }
 * 为什么?
 * 因为标准格式有参构造器的赋值语句,它永远是最后执行的
 * 它会覆盖掉其它任何new对象过程中的赋值方式
 *
 * 4.标准格式构造器,IDEA提供了自动生成的快捷键: Alt + Insert(Ins/Fn)
 *      以后建议大家使用快捷键自动生成构造器
 *      如无特殊需求,不要手写构造器
 *
 * 5.new对象的时候，JVM自动去调用这个方法，构造方法无法通过普通方法的调用方式调用。
 *  构造器不是给程序员去调用的，但是程序员可以指示JVM在创建对象时，用哪个构造器给成员变量赋值！
 *
 *
 * @since 09:26
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 18岁的Java老师对象
        Teacher t1 = new Teacher();
        t1.age = 18;
        t1.course = "Java";
        // 28岁的C++老师对象
        Teacher t2 = new Teacher();
        t2.age = 28;
        t2.course = "C++";
        // 30岁的Python老师对象
        Teacher t3 = new Teacher();
        t3.age = 30;
        t3.course = "Python";

        t1.teach();
        t2.teach();
        t3.teach();

        System.out.println("--------------");
        Teacher t4 = new Teacher(18, "数学");
        t4.teach();

        Teacher t5 = new Teacher("物理");
        System.out.println(t5.course);
    }
}

class Teacher {
    String name;
    String course;
    int age;

    public void teach() {
        System.out.println("这个" + age + "岁的老师,正在讲" + course);
    }

    // 无参构造器
    public Teacher() {
    }

    // 有参构造器,完成course,age的赋值
    public Teacher(int age, String course) {
        this.course = course;
        this.age = age;
    }

    // 有参构造器,完成course的赋值
    public Teacher(String course) {
        this.course = course;
    }

    // 三参构造器
    public Teacher(String name, String course, int age) {
        this.name = name;
        this.course = course;
        this.age = age;
    }
    // 有参构造器,完成name的赋值,这不行,因为形参名不同,不是方法重载
    /*public Teacher(String name) {
        this.name = name;
    }*/
}